#ifndef _COOLANGAGE_EXPRESSION_H
#define _COOLANGAGE_EXPRESSION_H

#include <vector>

namespace COOLangage {
  class Expression;
  class Appel;
  class Operateur;
  class OperateurUnaire;
  class OperateurBinaire;
  class Variable;
  template<typename K> class Litteral;
  class LitEntier;
  class LitFlottant;
}

#include "VisitorExpression.h"

namespace COOLangage {

  class Expression {
  protected:
    Expression();
  public:
    virtual ~Expression() throw();

    virtual VisitorResult visit(VisitorExpression *visitor);
  };


  // -------------------------------------------------------------------------------
  class Appel : public Expression {
    char *methodname;
    std::vector<Expression*> arguments;
  public:
    Appel(const char* name);
    virtual ~Appel() throw();
    
    void addArgument(Expression *expr);
    
    const std::vector<Expression*> getArguments() const;
    
    const char* getMethodName() const;
    
    int size() const;
    Expression* operator[](int index) const;

    VisitorResult visit(VisitorExpression *visitor) ;
    
  };

  // -------------------------------------------------------------------------------
  template<typename K> class Litteral : public Expression {
    K value;
  public:
    Litteral(K value = 0) : value(value) { }
    virtual ~Litteral() throw() { }

    K getValue() const { return value; }
    void setValue(K value) const { this->value = value; }
  };
  // -------------------------------------------------------------------------------
  class LitEntier : public Litteral<int> { 
  public:
    LitEntier(int e) : Litteral<int>(e) { }
    
    VisitorResult visit(VisitorExpression *visitor);
  };
  class LitFlottant : public Litteral<float> { 
    LitFlottant(float e) : Litteral<float>(e) { }

    VisitorResult visit(VisitorExpression *visitor);
  };
  // -------------------------------------------------------------------------------
  class Operateur : public Expression {
    char *symbol;
  public:
    Operateur(const char* const symbol);
    virtual  ~Operateur() throw();

    char* getSymbol() const { return symbol ; }

    virtual int size() const = 0;

    VisitorResult visit(VisitorExpression *visitor);
  };

  // -------------------------------------------------------------------------------
  class OperateurUnaire : public Operateur {
    Expression *operand;
  public:
    OperateurUnaire(const char* symbol, Expression *operand);
    virtual ~OperateurUnaire() throw();

    int size() const ;
    Expression* getOperand() const;

    VisitorResult visit(VisitorExpression *visitor);
  };


  // -------------------------------------------------------------------------------
  class OperateurBinaire : public Operateur {
    Expression *left;
    Expression *right;
  public:
    OperateurBinaire(const char* symbol, Expression *left, Expression* right);
    virtual ~OperateurBinaire() throw();

    int size() const;
    Expression* getLeft() const;
    Expression* getRight() const;

    VisitorResult visit(VisitorExpression *visitor);
  };


  // -------------------------------------------------------------------------------
  class Variable : public Expression {
    char *name;
  public:
    Variable(const char* name);
    virtual ~Variable() throw() ;

    const char* getName() const;

    VisitorResult visit(VisitorExpression *visitor);    
  };

}


#endif
